package com.shihang.core.apollo.spring;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.shihang.core.apollo.constant.Env;
import com.shihang.core.apollo.util.PropertyUtils;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Set;


@Order(-1)
public class ApolloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {


    private org.slf4j.Logger logger = LoggerFactory.getLogger(ApolloApplicationContextInitializer.class);


    @Override
    public void initialize(ConfigurableApplicationContext context) {
        ConfigurableEnvironment environment = context.getEnvironment();
        this.initializeSystemProperty(environment);
    }

    void initializeSystemProperty(ConfigurableEnvironment environment) {
        String applicationName = environment.getProperty(ApolloConstant.SpringApplicationName);
        PropertyUtils.setDefaultInitProperty(ApolloConstant.AppId, applicationName);
        String env = getEnv(environment);
        PropertyUtils.setDefaultInitProperty(ApolloConstant.Env, env);
        //默认设置app.id
        //默认设置apollo.meta
        String apolloMeta = StringUtils.isEmpty(System.getenv("APOLLO_META")) ? environment.getProperty(ApolloConstant.SHIHANG_APOLLOMETA) : System.getenv("APOLLO_META");
        PropertyUtils.setDefaultInitProperty(ApolloConstant.ApolloMeta, StringUtils.isEmpty(apolloMeta) ? ApolloConstant.Default_ApolloMeta : apolloMeta);
        //默认设置 apollo.bootstrap.enabled=true
        PropertyUtils.setDefaultInitProperty(ApolloConstant.ApolloBootstrapEnabled, "false");
        //默认设置 namespaces
        String namespaces = environment.getProperty(ApolloConstant.SHIHANG_APOLLOBOOTSTRAPNAMESPACES);
        PropertyUtils.setDefaultInitProperty(ApolloConstant.ApolloBootstrapNamespaces, StringUtils.isEmpty(namespaces) ? "application" : namespaces);
        PropertyUtils.setDefaultInitProperty(ApolloConstant.ApolloBootstrapEagerLoadEnabled, "true");
        this.registerToSystemProperty(environment);
        this.registerConfigChangedListener(environment);
    }


    private void registerToSystemProperty(ConfigurableEnvironment environment) {
        for (String namespace : environment.getProperty(ApolloConstant.ApolloBootstrapNamespaces, "").split(",")) {
            if (StringUtils.isEmpty(namespace)) {
                continue;
            }
            Config config = ConfigService.getConfig(namespace);
            Set<String> propertyNames = config.getPropertyNames();
            if (CollectionUtils.isEmpty(propertyNames)) {
                continue;
            }
            propertyNames.stream().forEach(c -> {
                String configString = config.getProperty(c, "");
                String configKey = c.toLowerCase();
                /**
                 * 设置中间件信息到 系统变量
                 */
                boolean isNotStartLog = !configKey.startsWith("loggers.root") && !configKey.startsWith("log.root.level");
                boolean isFromShihang = configKey.startsWith("raptor");
                if (isNotStartLog && isFromShihang) {
                    System.setProperty(c, configString);
                    logger.info(" set  key--->" + c + ",value--->" + configString + "  System value");
                }

            });
        }
    }


    private void registerConfigChangedListener(ConfigurableEnvironment environment) {
        String applicationName = environment.getProperty(ApolloConstant.SpringApplicationName);
        for (String namespace : environment.getProperty(ApolloConstant.ApolloBootstrapNamespaces, "").split(",")) {
            if (StringUtils.isEmpty(namespace)) {
                continue;
            }
            Config config = ConfigService.getConfig(namespace);
            config.addChangeListener(changeEvent -> {
                for (String key : changeEvent.changedKeys()) {
                    ConfigChange change = changeEvent.getChange(key);
                    logger.info(String.format(applicationName + " 监听到apollo配置修改,key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType()));
                }
            });
        }
    }

    private String getEnv(ConfigurableEnvironment environment) {
        String osenv = System.getenv("ENV");
        if (!StringUtils.isEmpty(osenv)) {
            return Env.getEnv(osenv);
        } else {
            String profile = environment.getProperty(ApolloConstant.SpringProfilesActive);
            return Env.getEnv(profile);
        }
    }
}
